import bcrypt from "bcryptjs"; // 推荐使用bcryptjs（比bcrypt更易安装）
import jwt from "jsonwebtoken";
import { Context, Next } from "koa";
import env from "../config/env";
import { UserService } from "../services/user.service";

// Token payload接口
export interface TokenPayload {
  userId: number;
  role: string;
}

/**
 * 认证相关工具类：密码加密/比对、手机号脱敏、JWT token生成和验证
 */
export class AuthUtil {
  /**
   * 密码加密（仅加密，不解密，登录时用comparePassword比对）
   * @param rawPassword 原始明文密码
   * @returns 加密后的密码（带盐值）
   */
  public static async hashPassword(rawPassword: string): Promise<string> {
    const saltRounds = 10; // 盐值 rounds（越大越安全，10是平衡安全与性能的推荐值）
    return bcrypt.hash(rawPassword, saltRounds);
  }

  /**
   * 密码比对（明文密码 vs 加密密码）
   * @param rawPassword 前端传入的明文密码
   * @param hashedPassword 数据库中存储的加密密码
   * @returns 是否一致（boolean）
   */
  public static async comparePassword(
    rawPassword: string,
    hashedPassword: string
  ): Promise<boolean> {
    return bcrypt.compare(rawPassword, hashedPassword);
  }

  /**
   * 手机号脱敏（隐藏第4-7位，如13812345678 → 138****5678）
   * @param mobile 原始手机号
   * @returns 脱敏后的手机号
   */
  public static maskMobile(mobile: string): string {
    if (!/^1[3-9]\d{9}$/.test(mobile)) return mobile; // 非手机号不处理
    return mobile.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
  }

  /**
   * 生成JWT token
   * @param userId 用户ID
   * @param role 用户角色
   * @returns JWT token字符串
   */
  public static generateToken(userId: number, role: string): string {
    const payload: TokenPayload = {
      userId,
      role,
    };

    // 使用环境配置中的JWT密钥
    return jwt.sign(payload, env.JWT_SECRET);
  }

  /**
   * 验证JWT token
   * @param token JWT token字符串
   * @returns 解析后的payload或null
   */
  public static verifyToken(token: string): TokenPayload | null {
    try {
      return jwt.verify(token, env.JWT_SECRET) as TokenPayload;
    } catch (error) {
      return null;
    }
  }

  /**
   * 验证普通用户token的中间件
   */
  public static isNormal() {
    return async (ctx: Context, next: Next) => {
      const token = ctx.headers.authorization?.replace("Bearer ", "");

      if (!token) {
        ctx.status = 401;
        ctx.body = {
          code: 401,
          message: "未提供认证token",
        };
        return;
      }

      const payload = AuthUtil.verifyToken(token);
      if (!payload) {
        ctx.status = 401;
        ctx.body = {
          code: 401,
          message: "token无效或已过期",
        };
        return;
      }

      // 检查用户是否被禁用
      const isAvailable = await UserService.checkUserAvailable(payload.userId);
      if (!isAvailable) {
        ctx.status = 403;
        ctx.body = {
          code: 403,
          message: "用户已被禁用或已被删除",
        };
        return;
      }

      // 将用户信息添加到ctx.state
      ctx.state.authorization = {
        userId: payload.userId,
        role: payload.role,
      };

      await next();
    };
  }

  /**
   * 验证管理员用户token的中间件
   */
  public static isAdmin() {
    return async (ctx: Context, next: Next) => {
      console.log("ctx.headers", ctx.headers);
      const token = ctx.headers.authorization?.replace("Bearer ", "");

      if (!token) {
        ctx.status = 401;
        ctx.body = {
          code: 401,
          message: "未提供认证token",
        };
        return;
      }

      const payload = AuthUtil.verifyToken(token);
      if (!payload) {
        ctx.status = 401;
        ctx.body = {
          code: 401,
          message: "token无效或已过期",
        };
        return;
      }

      // 检查用户是否被禁用
      const isAvailable = await UserService.checkUserAvailable(payload.userId);
      if (!isAvailable) {
        ctx.status = 403;
        ctx.body = {
          code: 403,
          message: "用户已被禁用或已被删除",
        };
        return;
      }

      // 检查是否为管理员
      if (payload.role !== "admin") {
        ctx.status = 403;
        ctx.body = {
          code: 403,
          message: "权限不足，需要管理员权限",
        };
        return;
      }

      // 将用户信息添加到ctx.state
      ctx.state.authorization = {
        userId: payload.userId,
        role: payload.role,
      };

      await next();
    };
  }

  /**
   * 获取token中的payload
   */
  public static getTokenPayLoad(ctx: Context): TokenPayload | null {
    const token = ctx.headers.authorization?.replace("Bearer ", "");
    if (!token) {
      return null;
    }
    return AuthUtil.verifyToken(token);
  }
}
